#include "cacheThread.h"
#include "cacheCommon.h"
#include "cacheCentral.h"
#include "cacheObjectPool.h"

//所有线程threadCache
threadCache* thread_heaps_ = nullptr;
size_t thread_heaps_count_ = 0;
std::mutex thread_mt_;
thread_local threadCache* threadcache_data_ = nullptr;


threadCache::threadCache()
:tid_(0)
,prev_(nullptr)
,next_(nullptr)
{

}

threadCache::~threadCache()
{

}

void* threadCache::allocate(size_t size)
{
    int idx = sizeClass::getIndex(size);
    if(idx == -1)
        return nullptr;
    
    void* ptr = free_list_[idx].pop();
    if(ptr)
        return ptr;
    
    return fetchFromCentral(size);
}

void threadCache::dellocate(void* ptr, size_t size)
{
    size_t idx = sizeClass::getIndex(size);
    if(idx < 0)
        return;
    
    free_list_[idx].push(ptr);

    //tcmalloc是 剩余数量 | 剩余缓存大小 -1 < 0就归还
    if(free_list_[idx].getNum() >= free_list_[idx].getMaxNum())
        releaseToCentral(free_list_[idx], size);
}

void* threadCache::fetchFromCentral(size_t size)
{
    size_t idx = sizeClass::getIndex(size);
    size_t num = std::min(free_list_[idx].getMaxNum(), sizeClass::SizeMoveNum(size));

    //start与end之间的内存块是切割好的
    void* start = nullptr;
    void* end = nullptr;
    size_t actulnum = centralCache::getInstance()->fetchRangeObj(start, end, num, sizeClass::getRoundUp(size));
    if(actulnum == 0)
        return nullptr;
    
    //拿一个出来
    void* obj = start;
    start = NextObj(start);
    actulnum--;

    //插入到threadCache
    if(actulnum > 0)
        free_list_[idx].pushRange(start, end, actulnum);
    
    if(num == free_list_[idx].getMaxNum())
        free_list_[idx].setMaxNum(num + 1);
    
    return obj;
}

void threadCache::releaseToCentral(freeList& fl, size_t size)
{
    size_t num = fl.getMaxNum();
    if(num == 0)
        return;
    
    void* start = nullptr;
    void* end = nullptr;
    size_t actual_num = fl.popRange(start, end, num);

    if(end)
    {
        centralCache::getInstance()->releaseRangeObj(start, size);
    }
}

threadCache* threadCache::createCacheIfNecessary()
{
    threadCache* head = nullptr;
    pthread_t mtid = pthread_self();

    std::lock_guard<std::mutex> mt(thread_mt_);

    threadCache* h = thread_heaps_;
    for(; h != nullptr; h = h->next_)
    {
        if(h->tid_ == mtid)
        {
            head = h;
            break;
        }
    }
    if(head == nullptr)
    {
        //mmap创建 TODO 需不需要优化，做成对象池 tcmalloc做的是对象池
        //head = (threadCache*)systemAllocBig(sizeof(threadCache));
        head = threadcache_allocator_.New();
        head->tid_ = mtid;
        head->next_ = thread_heaps_;
        head->prev_ = nullptr;
        
        if(thread_heaps_)
            thread_heaps_->prev_ = head;

        thread_heaps_ = head;
        thread_heaps_count_++;

        threadcache_data_ = head;
        //std::cout << pthread_self()  << ": threadcache: " << head << std::endl; 
    }
    return head;

}

threadCache* threadCache::getThreadCache()
{
    return threadcache_data_ != nullptr ? threadcache_data_ : createCacheIfNecessary();
}

